﻿using System;
using System.Globalization;
using Airborne.ScrumPoker.Model.TeamFoundation;
using Airborne.ScrumPoker.Module.Events;
using Airborne.ScrumPoker.Module.TeamFoundation.Properties;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Regions;
using Microsoft.Practices.Composite.Wpf.Commands;
using Microsoft.Practices.Composite.Wpf.Events;
using Microsoft.Practices.Unity;

namespace Airborne.ScrumPoker.Module.TeamFoundation.Controllers
{
    public class WorkItemController : IWorkItemController, IDisposable
    {

        #region Fields

        private IRegionManager RegionManager { get; set; }
        private IEventAggregator EventAggregator { get; set; }
        private IUnityContainer Container { get; set; }
        private DelegateCommand<object> ConnectToServerCommand;
        private ITeamFoundationProxy TeamProxy { get; set; }
        private Views.IWorkItemSelectView WorkItemSelectView { get; set; }

        #endregion

        #region Constructor
        public WorkItemController(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer container, ITeamFoundationProxy teamProxy)
        {
            RegionManager = regionManager;
            EventAggregator = eventAggregator;
            Container = container;

            TeamProxy = teamProxy;

            ConnectToServerCommand = new DelegateCommand<object>(ConnectToServer, (x) => { return !TeamProxy.IsConnected; });
            TeamFoundationCommands.ConnectToServerCommand.RegisterCommand(ConnectToServerCommand);
        }
        #endregion

        #region Methods

        private void SubscribeToEvents()
        {
            EventAggregator.GetEvent<GenericEvent<int>>().Subscribe(NextWorkItemRequested, ThreadOption.PublisherThread, true, p => p.Topic == EventTopics.NextWorkItemRequested);
        }

        private void NextWorkItemRequested(EventParameters<int> step)
        {
            WorkItemSelectView.ForceNextWorkItemSelection(step.Value);  
        }


        private void ShowWorkItemView()
        {
            WorkItemSelectView = Container.Resolve<Views.IWorkItemSelectView>();
            RegisterWorkItemEvents(WorkItemSelectView);
            RegionManager.Regions[RegionNames.TeamFoundation].Add(WorkItemSelectView);
        }

        private void RegisterWorkItemEvents(Views.IWorkItemSelectView view)
        {
            view.ProjectSelected += ProjectSelected;
            view.WorkItemSelected += WorkItemSelected;
        }

        private void WorkItemSelected(object sender, ItemSelectedEventArgs<ITeamWorkItem> e)
        {
            GenericEvent<ITeamWorkItem> genericEvent = EventAggregator.GetEvent<GenericEvent<ITeamWorkItem>>();
            genericEvent.Publish(new EventParameters<ITeamWorkItem>(EventTopics.WorkItemSelected, e.SelectedItem));
        }

        private void ProjectSelected(object sender, ItemSelectedEventArgs<ITeamProject> e)
        {
            if (e.SelectedItem.IsNotNull())
            {
                ITeamWorkItem[] workItems = TeamProxy.GetWorkItems(e.SelectedItem);
                WorkItemSelectView.SetWorkItems(workItems);
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification="This represents a catch-all")]
        private void ConnectToServer(object sender)
        {
            if (TeamProxy.Connect())
            {
                try
                {
                    ITeamProject[] projects = TeamProxy.GetProjects();
                    SetProjects(projects);
                }
                catch (Exception ex)
                {
                    EventParameters<string> parameter = new EventParameters<string>(EventTopics.Error, string.Format( CultureInfo.CurrentUICulture, Resources.ErrorGeneralError, "list team projects", ex.ToString()));
                    EventAggregator.GetEvent<GenericEvent<string>>().Publish(parameter);
                }
                
            }
            else
            {
                EventParameters<string> parameter = new EventParameters<string>(EventTopics.Error, Resources.ErrorConnectingToTeamFoundationServer);
                EventAggregator.GetEvent<GenericEvent<string>>().Publish(parameter);
            }
        }

        private void SetProjects(ITeamProject[] projects)
        {
            Guard.IsNotNull(projects, "projects");
            WorkItemSelectView.SetProjects(projects);
        }
        #endregion

        #region IWorkItemController Members

        public void Run()
        {
            ShowWorkItemView();
            SubscribeToEvents();
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                TeamFoundationCommands.ConnectToServerCommand.UnregisterCommand(ConnectToServerCommand);
                EventAggregator.GetEvent<GenericEvent<int>>().Unsubscribe(NextWorkItemRequested);
            }
        }
        #endregion

    }
}
